package com.ruoyi.business.listener;

import com.alibaba.fastjson.JSON;
import com.ruoyi.business.constant.TradeConstants;
import com.ruoyi.business.domain.BusinessTradeConfig;
import com.ruoyi.business.domain.BusinessTradeRecord;
import com.ruoyi.business.dto.TicketDTO;
import com.ruoyi.business.enumType.PSIceOrderState;
import com.ruoyi.business.enumType.PSIceOrderType;
import com.ruoyi.business.enumType.TriggerType;
import com.ruoyi.business.service.IBusinessTradeConfigService;
import com.ruoyi.business.service.IBusinessTradeRecordService;
import com.ruoyi.business.service.OnTicketHandler;
import com.ruoyi.common.core.domain.AjaxResult;
import com.ruoyi.common.core.redis.RedisCache;
import com.ruoyi.common.utils.DateUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;

import java.math.BigDecimal;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.List;
import java.util.Objects;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;

/**
 * 对标的实时行情的数据进行 固定时间段的redis 存储
 */
@Component("ticketDataSaveSubscriber")
public class TicketDataSaveSubscriber implements OnTicketHandler {


    /**
     * 日志
     */
    private static final Logger logger = LoggerFactory.getLogger(TicketDataSaveSubscriber.class);

    @Autowired
    private RedisCache redisCache;

    @Autowired
    private IBusinessTradeConfigService businessTradeConfigService;

    @Autowired
    private IBusinessTradeRecordService businessTradeRecordService;

    @Value("${trade.rate}")
    private String tradeRate;


    /**
     * 执行行情存储和 开仓 平仓 任务
     *
     * @param message
     */
    @Override
    public synchronized void onTicket(String message) {
        logger.info("首次开仓或者平仓监听 开仓平仓存储开始，message{}", message);
        List<TicketDTO> ticketDTOS = JSON.parseArray(message, TicketDTO.class);
        TicketDTO ticketDTO = ticketDTOS.get(0);
        BigDecimal high = new BigDecimal(String.valueOf(ticketDTO.getHigh()));
        BigDecimal low = new BigDecimal(String.valueOf(ticketDTO.getLow()));
        BigDecimal price = new BigDecimal(String.valueOf(ticketDTO.getPrice()));
        Date marketTime = ticketDTO.getMarketTime();
        BigDecimal open = redisCache.getCacheObject(TradeConstants.SYMBOL_PRICE_OPEN_KEY + DateUtils.parseDateToStr(DateUtils.YYYY_MM_DD, marketTime));

        if (price.compareTo(BigDecimal.ZERO) == 0) {
            return;
        }

        // 执行开仓
        BusinessTradeConfig businessTradeConfig = new BusinessTradeConfig();
        businessTradeConfig.setStatus(0);
        businessTradeConfig.setStockCode(ticketDTO.getSymbol());
        List<BusinessTradeConfig> businessTradeConfigs = businessTradeConfigService.selectBusinessTradeConfigList(businessTradeConfig);

        for (BusinessTradeConfig tradeConfig : businessTradeConfigs) {
            AjaxResult ajaxResult = businessTradeRecordService.doBusinessTradeAuto(tradeConfig.getId(), PSIceOrderType.valueOf(tradeConfig.getFirstPositionType()), price, open, ticketDTO.getSymbol(), true, null);
            if (Objects.nonNull(ajaxResult)) {
                if ((int) ajaxResult.get(AjaxResult.CODE_TAG) == 200) {
                    logger.info("策略ID" + tradeConfig.getId() + ":首次开仓成功，委托数据：{}", JSON.toJSONString(ajaxResult.get(AjaxResult.DATA_TAG)));
                } else {
                    logger.error("策略ID" + tradeConfig.getId() + ":首次开仓失败,msg:{}", ajaxResult.get(AjaxResult.MSG_TAG));
                }
            }
        }

        // 平仓
        Date closePositionTime;
        Date nowTime;
        try {
            closePositionTime = DateUtils.parseDate("14:50:00", DateUtils.HH_MM_SS);
            nowTime = DateUtils.dateTime(DateUtils.HH_MM_SS, new SimpleDateFormat(DateUtils.HH_MM_SS).format(new Date()));
            if (nowTime.after(closePositionTime)) {
                logger.info("执行平仓开始，nowTime:{},closePositionTime:{}", nowTime, closePositionTime);
                // 获取当天内交易的单据信息  todo 后面设置定时任务 同步更新订单状态，所有单据在14：40 截至下单
                BusinessTradeRecord tradeRecordQuery = new BusinessTradeRecord();
                tradeRecordQuery.setTriggerType(TriggerType.AUTO_TAKE_POSITION_TRIGGER.toString());
                List<BusinessTradeRecord> businessTradeRecordList1 = businessTradeRecordService.selectTodayTradeRecord();
                businessTradeRecordList1 = businessTradeRecordList1.stream().filter(item -> !item.getPositionClosed()).filter(item -> TriggerType.AUTO_TAKE_POSITION_TRIGGER.equals(TriggerType.valueOf(item.getTriggerType()))).collect(Collectors.toList());
                // 未成交，撤单
                for (BusinessTradeRecord businessTradeRecord : businessTradeRecordList1) {
                    Integer delegateState = businessTradeRecord.getDelegateState();
                    PSIceOrderType psIceOrderType = PSIceOrderType.valueOf(businessTradeRecord.getDelegateType());
                    PSIceOrderType closePositionOrderType = PSIceOrderType.Buy;
                    BigDecimal closePositionPrice = price.multiply(new BigDecimal(tradeRate).multiply(new BigDecimal("0.01")).add(BigDecimal.ONE));

                    assert psIceOrderType != null;
                    if (psIceOrderType.equals(PSIceOrderType.Buy)) {
                        closePositionOrderType = PSIceOrderType.Sell;
                        closePositionPrice = price.multiply(BigDecimal.ONE.subtract(new BigDecimal(tradeRate).multiply(new BigDecimal("0.01"))));
                    }

                    // 对于未申报、正在申报、已申报、部分成交 进行撤单操作
                    if (delegateState == PSIceOrderState.Undeclared.value() || delegateState == PSIceOrderState.Declaring.value()
                            || delegateState == PSIceOrderState.Declared.value() || delegateState == PSIceOrderState.PartFilled.value()) {
//                        Integer dealVolume = businessTradeRecord.getDealVolume();
//                        Integer delegateVolume = businessTradeRecord.getDelegateVolume();
//                        if (!dealVolume.equals(delegateVolume)) {
                        businessTradeRecordService.cancleOrder(businessTradeRecord);
                        continue;
//                        }
                    }
                    // 平仓 对于已成交和部分撤单
                    if (delegateState == PSIceOrderState.Filled.value() || delegateState == PSIceOrderState.PartCanceled.value()) {
                        BusinessTradeRecord businessTradeCloseRecord = new BusinessTradeRecord();
                        businessTradeCloseRecord.setStrategyGroupId(businessTradeRecord.getStrategyGroupId());
                        businessTradeCloseRecord.setStrategyId(businessTradeRecord.getStrategyId());
                        businessTradeCloseRecord.setStockCode(businessTradeRecord.getStockCode());
                        businessTradeCloseRecord.setDelegateType(closePositionOrderType.value());
                        businessTradeCloseRecord.setDelegateVolume(businessTradeRecord.getDealVolume());
                        businessTradeCloseRecord.setTriggerType(TriggerType.TIME_CLOSE_POSITION_TRIGGER.toString());
                        businessTradeCloseRecord.setPrice(closePositionPrice);
                        businessTradeCloseRecord.setPositionClosed(true);
                        businessTradeCloseRecord.setRelatedOrderNo(businessTradeRecord.getOrderNo());
                        businessTradeCloseRecord.setDelegateCode(businessTradeRecord.getDelegateCode());
                        businessTradeCloseRecord.setClientName(businessTradeRecord.getClientName());
                        businessTradeCloseRecord.setPassword(businessTradeRecord.getPassword());

                        AjaxResult ajaxResultPingSell = businessTradeRecordService.tradeAndInsertBusinessTradeRecord(businessTradeCloseRecord);

                        if ((int) ajaxResultPingSell.get(AjaxResult.CODE_TAG) == 200) {
                            businessTradeRecord.setPositionClosed(true);
                            businessTradeRecordService.updateBusinessTradeRecord(businessTradeRecord);
                            logger.info("执行平仓成功，businessTradeRecord：{}", JSON.toJSONString(ajaxResultPingSell.get(AjaxResult.DATA_TAG)));
                        } else {
                            logger.error("执行平仓失败，msg：{}", ajaxResultPingSell.get(AjaxResult.MSG_TAG));
                        }
                    }
                }

            }
        } catch (Exception e) {
            logger.error("平仓出错:{}", e.getMessage());
            e.printStackTrace();
        }

    }
}

